﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PGMHelper;
using System.Windows.Forms.DataVisualization.Charting;

namespace GBCodeSpecturmDemo
{
    /// <summary>
    /// 国家反应谱
    /// </summary>
    public class GBCodeSpectrum
    {
        #region Variables

        /// <summary>
        /// 阻尼比
        /// </summary>
        private double DampingRatio { set; get; }

        /// <summary>
        /// 特征周期值
        /// </summary>
        private double ModelTg { set; get; }

        /// <summary>
        /// 地震影响系数最大值
        /// </summary>
        private double ModelAfaMax { set; get; }

        /// <summary>
        /// 6s后是否拉平处理
        /// </summary>
        private bool is6Horizontal { set; get; }

        /// <summary>
        /// 反应谱分析结果
        /// </summary>
        private List<SpectrumParam> SpectrumValues { set; get; }

        /// <summary>
        /// 周期长度
        /// </summary>
        private double PeriodLength { set; get; }

        /// <summary>
        /// 周期增量
        /// </summary>
        private double DeltaPeriod { set; get; }

        /// <summary>
        /// 对象描述
        /// </summary>
        public string Descp
        {
            get
            {
                return string.Format("Afamax{0} Tg{1} Damp{2}",
                    this.ModelAfaMax, this.ModelTg, this.DampingRatio);
            }
            set
            { }
        }

        #endregion

        #region Properties

        /// <summary>
        /// 下降斜率调整系数
        /// </summary>
        private double Factor1
        {
            get
            {
                var value = 0.02 + (0.05 - this.DampingRatio) / (4 + 32 * this.DampingRatio);
                return value < 0 ? 0 : value;
            }
        }

        /// <summary>
        /// 阻尼调整系数
        /// </summary>
        private double Factor2
        {
            get
            {
                var value = 1 + (0.05 - this.DampingRatio) / (0.08 + 1.6 * this.DampingRatio);
                return value < 0.55 ? 0.55 : value;
            }
        }

        /// <summary>
        /// 衰减指数
        /// </summary>
        private double Gamma
        {
            get
            {
                return 0.9 + (0.05 - this.DampingRatio) / (0.3 + 6 * this.DampingRatio);
            }
        }

        #endregion

        /// <summary>
        /// 获得反应谱结果
        /// </summary>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public List<double> GetValueList(string propertyName)
        {
            return this.SpectrumValues.GetPropertyList(propertyName).ConvertAll(d => (double)d);
        }

        /// <summary>
        /// 绘图
        /// </summary>
        /// <param name="chart"></param>
        public void ToChart(Chart chart)
        {
            try
            {
                chart.AddSeries(this.Descp, SeriesChartType.Line, 2);
                chart.Series[this.Descp].Points.DataBindXY(this.GetValueList("Period"),
                    this.GetValueList("Afa"));
            }
            catch(Exception ex)
            {
                MessageBoxExtern.Warnning(ex.Message);
            }
           
        }

        /// <summary>
        /// 根据周期计算影响系数
        /// </summary>
        /// <param name="period"></param>
        /// <returns></returns>
        private double PeriodToAfa(double period)
        {
            //5Tg到6.0规范公式
            Func<double, double> getAfa = subPeriod =>
            {
                return (this.Factor2 * Math.Pow(0.2, this.Gamma) - this.Factor1 * (subPeriod - 5 * this.ModelTg)) * this.ModelAfaMax;
            };
            //周期小于零不存在
            if (period < 0) return -1;
            //0到0.1
            else if (period <= 0.1)
            {
                return (this.Factor2 * this.ModelAfaMax - 0.45 * this.ModelAfaMax) / 0.1 * period + 0.45 * this.ModelAfaMax;
            }
            //0.1到Tg
            else if (period <= this.ModelTg) return this.Factor2 * this.ModelAfaMax;
            //Tg到5Tg
            else if (period <= 5 * this.ModelTg)
                return Math.Pow(this.ModelTg / period, this.Gamma) * this.Factor2 * this.ModelAfaMax;
            //6s内
            else if (period <= 6) return getAfa(period);
            //6s外
            else return this.is6Horizontal ? getAfa(6) : getAfa(period);
        }

        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="period"> 周期 </param>
        /// <param name="Afa"> 影响系数 </param>
        private void Add(double period, double afa)
        {
            this.SpectrumValues.Add(new SpectrumParam
            {
                Period = period,
                Afa = afa,
            });
        }

        /// <summary>
        /// 空的构造函数
        /// </summary>
        public GBCodeSpectrum()
        {
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="tg"> 特征周期 </param>
        /// <param name="afaMax"> 影响系数最大值 </param>
        /// <param name="dampRatio"> 阻尼比 </param>
        /// <param name="is6Horizontal"> 周期6s后是否拉平 </param>
        /// <param name="periodLength"> 周期长度 </param>
        /// <param name="deltaPeriod"> 周期增量 </param>
        public GBCodeSpectrum(double tg, double afaMax, double dampRatio, bool is6Horizontal,
            double periodLength, double deltaPeriod)
        {
            //初始化
            this.SpectrumValues = new List<SpectrumParam>();
            //设定信息
            this.ModelAfaMax = afaMax;
            this.ModelTg = tg;
            this.DampingRatio = dampRatio;
            this.is6Horizontal = is6Horizontal;
            this.PeriodLength = periodLength;
            this.DeltaPeriod = deltaPeriod;
            //数据点数目
            var prtNum = (int)(this.PeriodLength / this.DeltaPeriod);
            //添加反应谱值
            for (int prt = 1; prt <= prtNum; prt++)
                this.Add(this.DeltaPeriod * prt, this.PeriodToAfa(this.DeltaPeriod * prt));
        }
    }
}
